Skip to content

[client] Android - Reuse the profile's account for Android SSO logins - #6988

Open
pappz wants to merge 2 commits into
mainfrom
fix/android-login-hint
Open

[client] Android - Reuse the profile's account for Android SSO logins#6988
pappz wants to merge 2 commits into
mainfrom
fix/android-login-hint

Conversation

@pappz

@pappz pappz commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

The Android binding never recorded which account a profile belongs to, so every interactive login and every session extend went to the IdP with no login_hint. With nothing to go on the IdP picks an account itself, which on a session extend means re-authenticating an account the profile is already signed in with.

Store the email the PKCE flow already parses out of the ID token, and pass it back as the hint on later flows. An empty hint stays meaningful: a fresh profile, or one that was logged out, deliberately leaves the choice to the IdP, which is how a profile changes accounts. Logout clears the stored email for that reason — while it is on disk it would steer the next login straight back into the account just logged out of.

The email is keyed off the profile's config path rather than the active profile: Auth.login runs in a goroutine, so the active profile can change under a flow already in flight. It lands in .account.json, not the .state.json desktop uses for the same data — there the email and the engine's state manager sit in different directories, but on Android both resolve under files/, and the state manager rewrites the whole file from its own keys.

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)
  • This change does not modify the public API, gRPC protocols, functionality behavior, CLI / service flags, or introduce a new feature — OR I have discussed it with the NetBird team beforehand (link the issue / Slack thread in the description). See CONTRIBUTING.md.

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • New Features

    • Added account email and active-status details to Android profile information.
    • Improved SSO sign-in and session renewal by restoring the previously used account as a login hint.
    • Added Android-specific profile email persistence with automatic cleanup on logout.
  • Bug Fixes

    • Profile email persistence failures now generate warnings without blocking login or logout.
    • More robust handling of missing/unreadable stored account data and safe cleanup when logout is repeated.
  • Tests

    • Added unit tests covering account-file naming, email read/write, and logout/idempotency behavior.

The Android binding never recorded which account a profile belongs to, so
every interactive login and every session extend went to the IdP with no
login_hint. With nothing to go on the IdP picks an account itself, which on a
session extend means re-authenticating an account the profile is already
signed in with.

Store the email the PKCE flow already parses out of the ID token, and pass it
back as the hint on later flows. An empty hint stays meaningful: a fresh
profile, or one that was logged out, deliberately leaves the choice to the
IdP, which is how a profile changes accounts. Logout clears the stored email
for that reason — while it is on disk it would steer the next login straight
back into the account just logged out of.

The email is keyed off the profile's config path rather than the active
profile: Auth.login runs in a goroutine, so the active profile can change
under a flow already in flight. It lands in <profile>.account.json, not the
<profile>.state.json desktop uses for the same data — there the email and the
engine's state manager sit in different directories, but on Android both
resolve under files/, and the state manager rewrites the whole file from its
own keys.
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9ba9851d-4282-4e20-a64a-54cdd482e820

📥 Commits

Reviewing files that changed from the base of the PR and between 40adcaa and 23c9828.

📒 Files selected for processing (2)
  • client/android/client.go
  • client/android/session.go

📝 Walkthrough

Walkthrough

Android clients now retain each profile’s configuration path and account email, expose email and active status in profile metadata, clear stored email on logout, and reuse the email as an SSO login hint during login and session extension.

Changes

Android profile authentication

Layer / File(s) Summary
Profile email storage
client/android/profile_state.go
Per-profile account files support reading, writing, and removing persisted account emails.
Profile metadata and logout
client/android/profile_manager.go
Profiles expose email and active status, and logout removes stored account email with warning-only failure handling.
Authentication hint flow
client/android/client.go, client/android/login.go, client/android/session.go
Configuration paths flow through client state and auth construction; login stores account email and reuses it as an OAuth login hint.
Profile email validation
client/android/profile_state_test.go
Tests validate account paths, collision avoidance, persistence, removal, and empty-email behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Auth
  participant OAuth
  participant ProfileState
  Client->>Auth: pass cfgPath to NewAuthWithConfig
  Auth->>ProfileState: readProfileEmail(cfgPath)
  ProfileState-->>Auth: stored account email
  Auth->>OAuth: set login hint
  OAuth-->>Auth: JWT token and account email
  Auth->>ProfileState: writeProfileEmail(cfgPath, email)
Loading

Possibly related PRs

Suggested reviewers: lixmal

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The change is described, but the required issue ticket and stack sections are empty, so the template is only partially filled. Add the issue ticket/link and stack details, and place the summary under 'Describe your changes' so the template is fully completed.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: reusing stored Android account email as the SSO login hint.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/android-login-hint

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pappz pappz changed the title [client, android] Reuse the profile's account for Android SSO logins [client] Android - Reuse the profile's account for Android SSO logins Jul 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@client/android/profile_manager.go`:
- Around line 203-206: Update LogoutProfile’s removeProfileEmail cleanup path so
a failure is returned to the caller instead of being only logged and followed by
a successful nil return. Preserve the existing warning context, and ensure the
logout operation reports the cleanup error after key removal so callers can
retry and avoid stale login hints.

In `@client/android/session.go`:
- Around line 296-300: Update extendAuthSession around foregroundGetTokenInfo to
persist tokenInfo.Email only after engine.ExtendAuthSession succeeds. Reuse the
rejected-token protection established in Auth.login/client/android/login.go, and
ensure the selected email is stored for fresh, logged-out, or switched profiles
without persisting rejected tokens.
- Around line 296-300: Update ExtendAuthSession to obtain cfg and cfgPath from
one atomic stateSnapshot instead of calling configPathSnapshot separately; pass
the snapshot’s cfgPath value to NewAuthWithConfig so both configuration and
login hint data come from the same profile state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 26d59291-a456-4c0c-9681-dcd206d238dd

📥 Commits

Reviewing files that changed from the base of the PR and between c1f0006 and 40adcaa.

📒 Files selected for processing (6)
  • client/android/client.go
  • client/android/login.go
  • client/android/profile_manager.go
  • client/android/profile_state.go
  • client/android/profile_state_test.go
  • client/android/session.go

Comment thread client/android/profile_manager.go
Comment thread client/android/session.go
@github-actions

github-actions Bot commented Jul 30, 2026

Copy link
Copy Markdown

Release artifacts

Built for PR head 23c9828 in workflow run #17303.

Artifact Link
All release artifacts Download
Linux packages Download
Windows packages Download
macOS packages Download
UI artifacts Download
UI macOS artifacts Download

GHCR images (amd64)

This comment is updated by the Release workflow. Artifact links expire according to the workflow retention policy.

extendAuthSession took the config from stateSnapshot and the config path from a
second call, each acquiring the lock on its own. A profile switch landing
between the two swaps every field, which would authenticate with one profile's
config while reading the login hint from another profile's account file.

Replace configPathSnapshot with authSnapshot, which returns both from a single
critical section.
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant